home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / winsock / ircii2-6.zip / SRC\IRCII-2.6\SOURCE\CTCP.C < prev    next >
C/C++ Source or Header  |  1995-01-04  |  19KB  |  856 lines

  1. /*
  2.  * ctcp.c:handles the client-to-client protocol(ctcp). 
  3.  *
  4.  * Written By Michael Sandrof 
  5.  *
  6.  * Copyright(c) 1990 
  7.  *
  8.  * See the COPYRIGHT file, or do a HELP IRCII COPYRIGHT 
  9.  */
  10.  
  11. #ifndef lint
  12. static    char    rcsid[] = "@(#)$Id: ctcp.c,v 1.17 1994/10/08 13:38:59 mrg Stab $";
  13. #endif
  14.  
  15. #include "irc.h"
  16.  
  17. #ifndef _Windows
  18. #include <pwd.h>
  19. #endif
  20.  
  21. #ifdef HAVE_UNAME
  22. # include <sys/utsname.h>
  23. #endif
  24.  
  25. #include "ircaux.h"
  26. #include "hook.h"
  27. #include "crypt.h"
  28. #include "ctcp.h"
  29. #include "vars.h"
  30. #include "server.h"
  31. #include "status.h"
  32. #include "lastlog.h"
  33. #include "ignore.h"
  34. #include "output.h"
  35. #include "window.h"
  36. #include "dcc.h"
  37. #include "names.h"
  38. #include "parse.h"
  39.  
  40. #define    CTCP_SHUTUP    0
  41. #define    CTCP_VERBOSE    1
  42. #define    CTCP_NOREPLY    2
  43.  
  44. static    char    FAR CTCP_Reply_Buffer[BIG_BUFFER_SIZE + 1] = "";
  45.  
  46. static    void    do_new_notice_ctcp();
  47.  
  48. extern    void    strmcat();
  49.  
  50. /* forward declarations for the built in CTCP functions */
  51. static    char    *do_sed();
  52. static    char    *do_version();
  53. static    char    *do_clientinfo();
  54. static    char    *do_echo();
  55. static    char    *do_userinfo();
  56. static    char    *do_finger();
  57. static    char    *do_time();
  58. static    char    *do_atmosphere();
  59. static    char    *do_dcc();
  60. extern    char    *do_utc();
  61.  
  62. static CtcpEntry ctcp_cmd[] =
  63. {
  64.     { "SED",    "contains simple_encrypted_data",
  65.         CTCP_SHUTUP | CTCP_NOREPLY, do_sed },
  66.     { "VERSION",    "shows client type, version and environment",
  67.         CTCP_VERBOSE, do_version },
  68.     { "CLIENTINFO",    "gives information about available CTCP commands",
  69.         CTCP_VERBOSE, do_clientinfo },
  70.     { "USERINFO",    "returns user settable information",
  71.         CTCP_VERBOSE, do_userinfo },
  72.     { "ERRMSG",    "returns error messages",
  73.         CTCP_VERBOSE, do_echo },
  74.     { "FINGER",    "shows real name, login name and idle time of user",
  75.         CTCP_VERBOSE, do_finger },
  76.     { "TIME",    "tells you the time on the user's host",
  77.         CTCP_VERBOSE, do_time },
  78.     { "ACTION",    "contains action descriptions for atmosphere",
  79.         CTCP_SHUTUP, do_atmosphere },
  80.     { "DCC",    "requests a direct_client_connection",
  81.         CTCP_SHUTUP | CTCP_NOREPLY, do_dcc },
  82.     { "UTC",    "substitutes the local timezone",
  83.         CTCP_SHUTUP | CTCP_NOREPLY, do_utc },
  84.     { "PING",     "returns the arguments it receives",
  85.         CTCP_VERBOSE, do_echo },
  86.     { "ECHO",     "returns the arguments it receives",
  87.         CTCP_VERBOSE, do_echo }
  88. };
  89.  
  90. char    *ctcp_type[] =
  91. {
  92.     "PRIVMSG",
  93.     "NOTICE"
  94. };
  95.  
  96. static    char    FAR ctcp_buffer[BIG_BUFFER_SIZE + 1] = "";
  97.  
  98. /* This is set to one if we parsed an SED */
  99. int     sed = 0;
  100.  
  101. /*
  102.  * in_ctcp_flag is set to true when IRCII is handling a CTCP request.  This
  103.  * is used by the ctcp() sending function to force NOTICEs to be used in any
  104.  * CTCP REPLY 
  105.  */
  106. int    in_ctcp_flag = 0;
  107.  
  108. /*
  109.  * ctcp_last_reply_time: Used to stop flooding...  We only send one ctcp
  110.  * reply a second.. if the variable NOCTCP_FLOOD is set...  If the current
  111.  * second is still the same, we drop the request, and info the user.
  112.  */
  113. time_t    ctcp_last_reply_time = 0;
  114.  
  115. int    ctcp_dropped;
  116. int    not_warned = 0;
  117.  
  118. /*
  119.  * quote_it: This quotes the given string making it sendable via irc.  A
  120.  * pointer to the length of the data is required and the data need not be
  121.  * null terminated (it can contain nulls).  Returned is a malloced, null
  122.  * terminated string.   
  123.  */
  124. char    *ctcp_quote_it(str, len)
  125. char    *str;
  126. int    len;
  127. {
  128.     define_big_buffer(buffer);
  129.     char    *ptr;
  130.     int    i;
  131.  
  132.     ptr = buffer;
  133.     for (i = 0; i < len; i++)
  134.     {
  135.         switch (str[i])
  136.         {
  137.         case CTCP_DELIM_CHAR:
  138.             *(ptr++) = CTCP_QUOTE_CHAR;
  139.             *(ptr++) = 'a';
  140.             break;
  141.         case '\n':
  142.             *(ptr++) = CTCP_QUOTE_CHAR;
  143.             *(ptr++) = 'n';
  144.             break;
  145.         case '\r':
  146.             *(ptr++) = CTCP_QUOTE_CHAR;
  147.             *(ptr++) = 'r';
  148.             break;
  149.         case CTCP_QUOTE_CHAR:
  150.             *(ptr++) = CTCP_QUOTE_CHAR;
  151.             *(ptr++) = CTCP_QUOTE_CHAR;
  152.             break;
  153.         case '\0':
  154.             *(ptr++) = CTCP_QUOTE_CHAR;
  155.             *(ptr++) = '0';
  156.             break;
  157.         default:
  158.             *(ptr++) = str[i];
  159.             break;
  160.         }
  161.     }
  162.     *ptr = '\0';
  163.     str = (char *) 0;
  164.     malloc_strcpy(&str, buffer);
  165.     free_big_buffer(buffer);
  166.     return (str);
  167. }
  168.  
  169. /*
  170.  * ctcp_unquote_it: This takes a null terminated string that had previously
  171.  * been quoted using ctcp_quote_it and unquotes it.  Returned is a malloced
  172.  * space pointing to the unquoted string.  NOTE: a trailing null is added for
  173.  * convenied, but the returned data may contain nulls!.  The len is modified
  174.  * to contain the size of the data returned. 
  175.  */
  176. char    *ctcp_unquote_it(str, len)
  177. char    *str;
  178. int    *len;
  179. {
  180.     char    *buffer;
  181.     char    *ptr;
  182.     char    c;
  183.     int    i,
  184.         new_size = 0;
  185.  
  186.     buffer = (char *) new_malloc(sizeof(char) * *len);
  187.     ptr = buffer;
  188.     i = 0;
  189.     while (i < *len)
  190.     {
  191.         if ((c = str[i++]) == CTCP_QUOTE_CHAR)
  192.         {
  193.             switch (c = str[i++])
  194.             {
  195.             case CTCP_QUOTE_CHAR:
  196.                 *(ptr++) = CTCP_QUOTE_CHAR;
  197.                 break;
  198.             case 'a':
  199.                 *(ptr++) = CTCP_DELIM_CHAR;
  200.                 break;
  201.             case 'n':
  202.                 *(ptr++) = '\n';
  203.                 break;
  204.             case 'r':
  205.                 *(ptr++) = '\r';
  206.                 break;
  207.             case '0':
  208.                 *(ptr++) = '\0';
  209.                 break;
  210.             default:
  211.                 *(ptr++) = c;
  212.                 break;
  213.             }
  214.         }
  215.         else
  216.             *(ptr++) = c;
  217.         new_size++;
  218.     }
  219.     *ptr = '\0';
  220.     *len = new_size;
  221.     return (buffer);
  222. }
  223.  
  224. /*
  225.  * do_sed: Performs the Simple Encrypted Data trasfer for ctcp.  Returns in a
  226.  * malloc string the decryped message (if a key is set for that user) or the
  227.  * text "[ENCRYPTED MESSAGE]" 
  228.  */
  229. static    char    *do_sed(ctcp, from, to, args)
  230. CtcpEntry    *ctcp;
  231. char    *from,
  232.     *to,
  233.     *args;
  234. {
  235.     char    *key,
  236.         *crypt_who;
  237.     char    *ret = NULL;
  238.  
  239.     if (my_stricmp(to, get_server_nickname(from_server)))
  240.         crypt_who = to;
  241.     else
  242.         crypt_who = from;
  243.     if ((key = is_crypted(crypt_who)) && !(ret = crypt_msg(args, key, 0)))
  244.             malloc_strcpy(&ret, "[ENCRYPTED MESSAGE]");
  245.                 else
  246.                         sed = 1;
  247.     return (ret);
  248. }
  249.  
  250. /*
  251.  * do_clientinfo: performs the CLIENTINFO CTCP.  If cmd is empty, returns the
  252.  * list of all CTCPs currently recognized by IRCII.  If an arg is supplied,
  253.  * it returns specific information on that CTCP.  If a matching CTCP is not
  254.  * found, an ERRMSG ctcp is returned 
  255.  */
  256. static    char    *do_clientinfo(ctcp, from, to, cmd)
  257. CtcpEntry    *ctcp;
  258. char    *from,
  259.     *to,
  260.     *cmd;
  261. {
  262.     int    i;
  263.  
  264.     if (cmd && *cmd)
  265.     {
  266.         for (i = 0; i < NUMBER_OF_CTCPS; i++)
  267.         {
  268.             if (my_stricmp(cmd, ctcp_cmd[i].name) == 0)
  269.             {
  270.                 send_ctcp_reply(from, ctcp->name, "%s %s",
  271.                     ctcp_cmd[i].name, ctcp_cmd[i].desc);
  272.                 return NULL;
  273.             }
  274.         }
  275.         send_ctcp_reply(from, ctcp_cmd[CTCP_ERRMSG].name,
  276.                 "%s: %s is not a valid function",
  277.                 ctcp_cmd[CTCP_CLIENTINFO].name, cmd);
  278.     }
  279.     else
  280.     {
  281.         *buffer = '\0';
  282.         for (i = 0; i < NUMBER_OF_CTCPS; i++)
  283.         {
  284.             strmcat(buffer, ctcp_cmd[i].name, BIG_BUFFER_SIZE);
  285.             strmcat(buffer, " ", BIG_BUFFER_SIZE);
  286.         }
  287.         send_ctcp_reply(from, ctcp->name, 
  288.             "%s :Use CLIENTINFO <COMMAND> to get more specific \
  289. information",
  290.             buffer);
  291.     }
  292.     return NULL;
  293. }
  294.  
  295. /* do_version: does the CTCP VERSION command */
  296. static    char    *do_version(ctcp, from, to, cmd)
  297. CtcpEntry    *ctcp;
  298. char    *from,
  299.     *to,
  300.     *cmd;
  301. {
  302.     char    *tmp;
  303.  
  304. #ifdef HAVE_UNAME
  305.     struct utsname un;
  306.     char    *the_unix,
  307.         *the_version;
  308.  
  309.     if (uname(&un) < 0)
  310.     {
  311.         the_version = empty_string;
  312.         the_unix = "unknown";
  313.     }
  314.     else
  315.     {
  316.         the_version = un.release;
  317.         the_unix = un.sysname;
  318.     }
  319.     send_ctcp_reply(from, ctcp->name, "ircII %s %s %s :%s", irc_version, the_unix, the_version,
  320. #else
  321. #ifdef _Windows
  322.     send_ctcp_reply(from, ctcp->name, "ircII %s MS-Windows :%s", irc_version,
  323. #else
  324.     send_ctcp_reply(from, ctcp->name, "ircII %s *IX :%s", irc_version,
  325. #endif
  326. #endif
  327.         (tmp = get_string_var(CLIENTINFO_VAR)) ?  tmp : IRCII_COMMENT);
  328.     return NULL;
  329. }
  330.  
  331. /* do_time: does the CTCP TIME command --- done by Veggen */
  332. static    char    *do_time(ctcp, from, to, cmd)
  333. CtcpEntry    *ctcp;
  334. char    *from,
  335.     *to,
  336.     *cmd;
  337. {
  338.     time_t    tm = time((time_t *) 0);
  339.     char    *s, *t = ctime(&tm);
  340.  
  341.     if ((char *) 0 != (s = index(t, '\n')))
  342.         *s = '\0';
  343.     send_ctcp_reply(from, ctcp->name, "%s", t);
  344.     return NULL;
  345. }
  346.  
  347. /* do_userinfo: does the CTCP USERINFO command */
  348. static    char    *do_userinfo(ctcp, from, to, cmd)
  349. CtcpEntry    *ctcp;
  350. char    *from,
  351.     *to,
  352.     *cmd;
  353. {
  354.     send_ctcp_reply(from, ctcp->name, get_string_var(USERINFO_VAR));
  355.     return NULL;
  356. }
  357.  
  358. /*
  359.  * do_echo: does the CTCP ECHO, CTCP ERRMSG and CTCP ECHO commands. Does
  360.  * not send an error for ERRMSG and if the CTCP was sent to a channel.
  361.  */
  362. static    char    *do_echo(ctcp, from, to, cmd)
  363. CtcpEntry    *ctcp;
  364. char    *from,
  365.     *to,    
  366.     *cmd;
  367. {
  368.     if (!is_channel(to) || strcmp(from, "ERRMSG"))
  369.         send_ctcp_reply(from, ctcp->name, "%s", cmd);
  370.     return NULL;
  371. }
  372.  
  373. static    char    *do_finger(ctcp, from, to, cmd)
  374. CtcpEntry    *ctcp;
  375. char    *from,
  376.     *to,
  377.     *cmd;
  378. {
  379.     struct    passwd    *pwd;
  380.     time_t    diff;
  381.     int    uid;
  382.     char    c;
  383.  
  384.     /*
  385.      * sojge complained that ircII says 'idle 1 seconds'
  386.      * well, now he won't ever get the chance to see that message again
  387.      *   *grin*  ;-)    -lynx
  388.      *
  389.      * Made this better by saying 'idle 1 second'  -phone
  390.      */
  391.  
  392.     diff = time(0) - idle_time;
  393.     c = (diff == 1)? ' ': 's';
  394. #ifdef _Windows
  395.     send_ctcp_reply(from, ctcp->name,
  396.         "IRCII For MS-Windows User Idle %ld second%c",
  397.         diff, c);
  398. #else
  399.     uid = getuid();
  400. #ifdef DAEMON_UID
  401.     if (uid != DAEMON_UID)
  402.     {
  403. #endif /* DAEMON_UID */    
  404.         if ((pwd = getpwuid(uid)) != NULL)
  405.         {
  406.             char    *tmp;
  407.  
  408. #ifdef GECOS_DELIMITER
  409.             if ((tmp = index(pwd->pw_gecos, GECOS_DELIMITER)) != NULL)
  410. #else
  411.             if ((tmp = index(pwd->pw_gecos, ',')) != NULL)
  412. #endif /* GECOS_DELIMITER */
  413.                 *tmp = '\0';
  414.             send_ctcp_reply(from, ctcp->name,
  415.                 "%s (%s@%s) Idle %ld second%c", pwd->pw_gecos,
  416.                 pwd->pw_name, hostname, diff, c);
  417.         }
  418. #ifdef DAEMON_UID
  419.     }
  420.     else
  421.         send_ctcp_reply(from, ctcp->name,
  422.             "IRCII Telnet User (%s) Idle %ld second%c",
  423.             realname, diff, c);
  424. #endif /* DAEMON_UID */    
  425. #endif
  426.     return NULL;
  427. }
  428.  
  429. /*
  430.  * do_ctcp: handles the client to client protocol embedded in PRIVMSGs.  Any
  431.  * such messages are removed from the original str, so after do_ctcp()
  432.  * returns, str will be changed
  433.  */
  434. char    *do_ctcp(from, to, str)
  435. char    *from,
  436.     *to,
  437.     *str;
  438. {
  439.     int    i = 0,
  440.         ctcp_flag = 1;
  441.     char    *end,
  442.         *cmd,
  443.         *args,
  444.         *ptr;
  445.     char    *arg_copy = NULL;
  446.     int    flag;
  447.     int    messages = 0;
  448.  
  449.     flag = double_ignore(from, FromUserHost, IGNORE_CTCPS);
  450.  
  451.     if (!in_ctcp_flag)
  452.         in_ctcp_flag = 1;
  453.     *ctcp_buffer = '\0';
  454.     ctcp_dropped = 0;
  455.     while ((cmd = index(str, CTCP_DELIM_CHAR)) != NULL)
  456.     {
  457.         if (messages > 3)
  458.             break;
  459.         *(cmd++) = '\0';
  460.         strcat(ctcp_buffer, str);
  461.         if ((end = index(cmd, CTCP_DELIM_CHAR)) != NULL)
  462.         {
  463.             messages++;
  464.             if (!ctcp_dropped && (time(NULL) - ctcp_last_reply_time) < 2 && get_int_var(NO_CTCP_FLOOD_VAR))
  465.                 ctcp_dropped = 1;
  466.             if (!ctcp_dropped)
  467.                 not_warned = 1;
  468.             if (flag == IGNORED)
  469.                 continue;
  470.             *(end++) = '\0';
  471.             if ((args = index(cmd, ' ')) != NULL)
  472.                 *(args++) = '\0';
  473.             else
  474.                 args = empty_string;
  475.             malloc_strcpy(&arg_copy, args);
  476.             for (i = 0; i < NUMBER_OF_CTCPS; i++)
  477.             {
  478.                 if (strcmp(cmd, ctcp_cmd[i].name) == 0)
  479.                 {
  480.                 if (!ctcp_dropped || ctcp_cmd[i].flag & CTCP_NOREPLY)
  481.                 {
  482.         /*
  483.          * This test here to stop irc operators seeing ctcp replies
  484.          * when using global messages - phone, dec, 1992.
  485.          */
  486.                     if (*to != '$' && !(*to == '#' && !lookup_channel(to, from_server, 0)) &&
  487.                         (ptr = ctcp_cmd[i].func(&(ctcp_cmd[i]), from, to, arg_copy)))
  488.                     {
  489.                         strcat(ctcp_buffer, ptr);
  490.                         new_free(&ptr);
  491.                     }
  492.                     ctcp_flag = ctcp_cmd[i].flag;
  493.                     cmd = ctcp_cmd[i].name;
  494.                     break;
  495.                 }
  496.                     else if (get_int_var(VERBOSE_CTCP_VAR) && not_warned)
  497.                 {
  498.                     say("CTCP flood from %s", from);
  499.                     not_warned = 0;
  500.                 }
  501.                 }
  502.             }
  503.             new_free(&arg_copy);
  504.             if (!ctcp_dropped && in_ctcp_flag == 1 &&
  505.                 do_hook(CTCP_LIST, "%s %s %s %s", from, to, cmd,
  506.                 args) && get_int_var(VERBOSE_CTCP_VAR))
  507.             {
  508.                 int    lastlog_level;
  509.  
  510.                 lastlog_level = set_lastlog_msg_level(LOG_CTCP);
  511.                 message_from(NULL, LOG_CTCP);
  512.                 if (i == NUMBER_OF_CTCPS)
  513.                 {
  514.                     say("Unknown CTCP %s from %s to %s: %s%s",
  515.                         cmd, from, to, *args ? ": " :
  516.                         empty_string, args);
  517.                 }
  518.                 else if (ctcp_flag & CTCP_VERBOSE)
  519.                 {
  520.                     if (my_stricmp(to,
  521.                         get_server_nickname(from_server)))
  522.                         say("CTCP %s from %s to %s: %s",
  523.                             cmd, from, to, args);
  524.                     else
  525.                         say("CTCP %s from %s%s%s", cmd,
  526.                             from, *args ? ": " :
  527.                             empty_string, args);
  528.                 }
  529.                 set_lastlog_msg_level(lastlog_level);
  530.             }
  531.             str = end;
  532.         }
  533.         else
  534.         {
  535.             strcat(ctcp_buffer, CTCP_DELIM_STR);
  536.             str = cmd;
  537.         }
  538.     }
  539.     if (in_ctcp_flag == 1)
  540.         in_ctcp_flag = 0;
  541.     if (CTCP_Reply_Buffer && *CTCP_Reply_Buffer)
  542.         ctcp_last_reply_time = time(NULL);
  543.     strcat(ctcp_buffer, str);
  544.     send_to_server("%s", CTCP_Reply_Buffer);
  545.     *CTCP_Reply_Buffer = '\0';
  546.     return (ctcp_buffer);
  547. }
  548.  
  549. char    *do_notice_ctcp(from, to, str)
  550. char    *from,
  551.     *to,
  552.     *str;
  553. {
  554.     char    *cmd;
  555.  
  556.     in_ctcp_flag = -1;
  557.     *ctcp_buffer = '\0';
  558.     /*
  559.      * The following used to say "While". It now says "if" because people
  560.      * Started using CTCP ERRMSG replies to CTCP bomb. The effect of this
  561.      * is that IRCII users can only send one CTCP/message if they expect a
  562.      * reply. This shouldn't be a problem as that is the way IRCII operates
  563.      *
  564.      * Changed this behavouir to follow NO_CTCP_FLOOD
  565.      */
  566.  
  567.     if (get_int_var(NO_CTCP_FLOOD_VAR))
  568.     {
  569.         if ((cmd = index(str, CTCP_DELIM_CHAR)) != NULL)
  570.             do_new_notice_ctcp(from, to, &str, cmd);
  571.     }
  572.     else
  573.         while ((cmd = index(str, CTCP_DELIM_CHAR)) != NULL)
  574.             do_new_notice_ctcp(from, to, &str, cmd);
  575.     in_ctcp_flag = 0;
  576.     strcat(ctcp_buffer, str);
  577.     return (ctcp_buffer);
  578. }
  579.  
  580. static    void    do_new_notice_ctcp(from, to, str, cmd)
  581. char    *from,
  582.     *to,
  583.     **str,
  584.     *cmd;
  585. {
  586.     char    *end,
  587.         *args,
  588.         *ptr,
  589.         *arg_copy = NULL;
  590.     int    flags,
  591.         i,
  592.         lastlog_level;
  593.  
  594.     flags = 0;
  595.     *(cmd++) = '\0';
  596.     strcat(ctcp_buffer, *str);
  597.     if ((end = index(cmd, CTCP_DELIM_CHAR)) != NULL)
  598.     {
  599.         *(end++) = '\0';
  600.         if ((args = index(cmd, ' ')) != NULL)
  601.             *(args++) = '\0';
  602.         malloc_strcpy(&arg_copy, args);
  603.         for (i = 0; i < NUMBER_OF_CTCPS; i++)
  604.         {
  605.             if ((strcmp(cmd, ctcp_cmd[i].name) == 0) && ctcp_cmd[i].flag & CTCP_NOREPLY)
  606.             {
  607.                 if ((ptr = ctcp_cmd[i].func(&(ctcp_cmd[i]), from, to, arg_copy)) != NULL)
  608.                 {
  609.                     strcat(ctcp_buffer, ptr);
  610.                     new_free(&ptr);
  611.                     flags = ctcp_cmd[i].flag;
  612.                 }
  613.                 break;
  614.             }
  615.         }
  616.         new_free(&arg_copy);
  617.         if (!args)
  618.             args = empty_string;
  619.         if (do_hook(CTCP_REPLY_LIST, "%s %s %s", from, cmd,
  620.                 args) && !(flags & CTCP_NOREPLY))
  621.         {
  622.             if (!strcmp(cmd, "PING"))
  623.             {
  624.                 char    buf[20];
  625.                 time_t    timediff,
  626.                     currenttime;
  627.  
  628.                 currenttime = time(NULL);
  629.                 if (args && *args)
  630.                     timediff = currenttime -
  631.                         (time_t) atol(args);
  632.                 else
  633.                     timediff = (time_t) 0;
  634. #ifdef __MSDOS__
  635.                 sprintf(buf, "%ld second%s", timediff,
  636. #else
  637.                 sprintf(buf, "%d second%s", timediff,
  638. #endif
  639.                     (timediff == 1) ? "" : "s");
  640.                 args = buf;
  641.             }
  642.             lastlog_level = set_lastlog_msg_level(LOG_CTCP);
  643.             message_from(NULL, LOG_CTCP);
  644.             say("CTCP %s reply from %s: %s", cmd, from,
  645.                 args);
  646.             set_lastlog_msg_level(lastlog_level);
  647.         }
  648.         *str = end;
  649.     }
  650.     else
  651.     {
  652.         strcat(ctcp_buffer, CTCP_DELIM_STR);
  653.         *str = cmd;
  654.     }
  655. }
  656.  
  657. /* in_ctcp: simply returns the value of the ctcp flag */
  658. int    in_ctcp()
  659. {
  660.     return (in_ctcp_flag);
  661. }
  662.  
  663. /*
  664.  * do_atmosphere: does the CTCP ACTION command --- done by lynX
  665.  * Changed this to make the default look less offensive to people
  666.  * who don't like it and added a /on ACTION. This is more in keeping
  667.  * with the design philosophy behind IRCII
  668.  */
  669. static    char    *do_atmosphere(ctcp, from, to, cmd)
  670. CtcpEntry    *ctcp;
  671. char    *from,
  672.     *to,
  673.     *cmd;
  674. {
  675.     if (cmd && *cmd)
  676.     {
  677.         int old;
  678.  
  679.         old = set_lastlog_msg_level(LOG_ACTION);
  680.         if (is_channel(to))
  681.         {
  682.             message_from(to, LOG_ACTION);
  683.             if (do_hook(ACTION_LIST, "%s %s %s", from, to, cmd))
  684.             {
  685.                 if (is_current_channel(to, 0))
  686.                     put_it("* %s %s", from, cmd);
  687.                 else
  688.                     put_it("* %s:%s %s", from, to, cmd);
  689.             }
  690.         }
  691.         else
  692.         {
  693.             message_from(from, LOG_ACTION);
  694.             if (do_hook(ACTION_LIST, "%s %s %s", from, to, cmd))
  695.                 put_it("*> %s %s", from, cmd);
  696.         }
  697.         message_from(NULL, LOG_CRAP);
  698.         set_lastlog_msg_level(old);
  699.     }
  700.     return NULL;
  701. }
  702.  
  703. /*
  704.  * do_dcc: Records data on an incoming DCC offer. Makes sure it's a
  705.  *    user->user CTCP, as channel DCCs don't make any sense whatsoever
  706.  */
  707. static    char    *do_dcc(ctcp, from, to, args)
  708. CtcpEntry    *ctcp;
  709. char    *from,
  710.     *to,
  711.     *args;
  712. {
  713.     char    *type;
  714.     char    *description;
  715.     char    *inetaddr;
  716.     char    *port;
  717.     char    *size;
  718.  
  719.     if (my_stricmp(to, get_server_nickname(from_server)))
  720.         return NULL;
  721.     if (!(type = next_arg(args, &args)) ||
  722.             !(description = next_arg(args, &args)) ||
  723.             !(inetaddr = next_arg(args, &args)) ||
  724.             !(port = next_arg(args, &args)))
  725.         return NULL;
  726.     size = next_arg(args, &args);
  727.     register_dcc_offer(from, type, description, inetaddr, port, size);
  728.     return NULL;
  729. }
  730.  
  731. char    *do_utc(ctcp, from, to, args)
  732. CtcpEntry    *ctcp;
  733. char    *from,
  734.     *to,
  735.     *args;
  736. {
  737.     time_t    tm;
  738.     char    *date = NULL;
  739.  
  740.     if (!args || !*args)
  741.         return NULL;
  742.     tm = atol(args);
  743.     malloc_strcpy(&date, ctime(&tm));
  744.     date[strlen(date)-1] = '\0';
  745.     return date;
  746. }
  747.  
  748. /* These moved here because they belong here - phone */
  749.  
  750. /*
  751.  * send_ctcp_notice: A simply way to send CTCP replies.   I put this here
  752.  * rather than in ctcp.c to keep my compiler quiet 
  753.  */
  754. #ifdef USE_STDARG_H
  755. void    send_ctcp(char *type, char *to, char *datatag, char *format, ...)
  756. {
  757.     va_list vl;
  758. #else
  759. void    send_ctcp(type, to, datatag, format, arg0, arg1, arg2, arg3, arg4,
  760.     arg5, arg6, arg7, arg8, arg9)
  761. char    *type,
  762.     *to,
  763.     *datatag,
  764.     *format;
  765. char    *arg0,
  766.     *arg1,
  767.     *arg2,
  768.     *arg3,
  769.     *arg4,
  770.     *arg5,
  771.     *arg6,
  772.     *arg7,
  773.     *arg8,
  774.     *arg9;
  775. {
  776. #endif
  777.     define_big_buffer(putbuf);
  778.  
  779.     if (in_on_who)
  780.         return;    /* Silently drop it on the floor */
  781.     if (format)
  782.     {
  783. #ifdef USE_STDARG_H
  784.         va_start(vl, format);
  785.         vsprintf(putbuf, format, vl);
  786.         va_end(vl);
  787. #else
  788.         sprintf(putbuf, format, arg0, arg1, arg2, arg3, arg4, arg5,
  789.             arg6, arg7, arg8, arg9);
  790. #endif
  791.         send_to_server("%s %s :%c%s %s%c", type, to, CTCP_DELIM_CHAR,
  792.             datatag, putbuf, CTCP_DELIM_CHAR);
  793.     }
  794.     else
  795.         send_to_server("%s %s :%c%s%c", type, to, CTCP_DELIM_CHAR,
  796.             datatag, CTCP_DELIM_CHAR);
  797.     free_big_buffer(putbuf);
  798. }
  799.  
  800.  
  801. /*
  802.  * send_ctcp_notice: A simply way to send CTCP replies.   I put this here
  803.  * rather than in ctcp.c to keep my compiler quiet 
  804.  */
  805. #ifdef USE_STDARG_H
  806. void    send_ctcp_reply(char *to, char *datatag, char *format, ...)
  807. {
  808.     va_list vl;
  809. #else
  810. void    send_ctcp_reply(to, datatag, format, arg0, arg1, arg2, arg3, arg4,
  811.         arg5, arg6, arg7, arg8, arg9)
  812. char    *to,
  813.     *datatag,
  814.     *format;
  815. char    *arg0,
  816.     *arg1,
  817.     *arg2,
  818.     *arg3,
  819.     *arg4,
  820.     *arg5,
  821.     *arg6,
  822.     *arg7,
  823.     *arg8,
  824.     *arg9;
  825. {
  826. #endif
  827.     define_big_buffer(putbuf);
  828.  
  829.     if (in_on_who)
  830.     {
  831.         free_big_buffer(putbuf);
  832.         return;    /* Silently drop it on the floor */
  833.     }
  834.     if (!*CTCP_Reply_Buffer)
  835.         sprintf(CTCP_Reply_Buffer, "NOTICE %s :", to);
  836.     strmcat(CTCP_Reply_Buffer, "\001", BIG_BUFFER_SIZE);
  837.     strmcat(CTCP_Reply_Buffer, datatag, BIG_BUFFER_SIZE);
  838.     strmcat(CTCP_Reply_Buffer, " ", BIG_BUFFER_SIZE);
  839.     if (format)
  840.     {
  841. #ifdef USE_STDARG_H
  842.         va_start(vl, format);
  843.         vsprintf(putbuf, format, vl);
  844.         va_end(vl);
  845. #else
  846.         sprintf(putbuf, format, arg0, arg1, arg2, arg3, arg4, arg5,
  847.             arg6, arg7, arg8, arg9);
  848. #endif
  849.         strmcat(CTCP_Reply_Buffer, putbuf, BIG_BUFFER_SIZE);
  850.     }
  851.     else
  852.         strmcat(CTCP_Reply_Buffer, putbuf, BIG_BUFFER_SIZE);
  853.     strmcat(CTCP_Reply_Buffer, "\001", BIG_BUFFER_SIZE);
  854.     free_big_buffer(putbuf);
  855. }
  856.